<?php
/**
 * Created by PhpStorm.
 * User: xmy2
 * Date: 18-8-11
 * Time: 下午12:21
 */

namespace vola;

class Template
{
    // 扩充加入这里
    use tpl\Query;
    private static $init;
    private $tplpath = '';
    private $tmpfile;
    private $isstatic = false;
    private $com = [];
    private $assign = [];
    private $tpl = '';
    private $runtime = '';
    private $singleKey = false;
    private $cache_tpl = '';
    private $update_file_list = [];
    private $isMust = false;
    private $user_call = [];

    public function __construct()
    {
        $this->runtime = Container::get('app')->getTplRuntimepath();
    }

    public function tpl($file = '')
    {
        if (!file_exists($file)) {
            Error::the('Template', $file . ' not found');
        }

        if (!file_exists($this->runtime . '/index.html')) {
            file_put_contents($this->runtime . '/index.html', '');
        }

        $this->tpl = $file;
        $this->cache_tpl = $this->runtime . DIRECTORY_SEPARATOR . Loadder::crypt($this->tpl, Loadder::HAVAL) . '.php';
        return $this;
    }

    /**
     * @return string
     */
    public function get()
    {
        return $this->cache_tpl;
    }

    private function runShow($content = '', $cache = '')
    {
        // 只检查第一层的
        if (strpos($content, '@include ') !== false) {
            $content = $this->includeCommand($content);
        }

        $content = $this->showVar($content);
        $content = $this->showFuc($content);
        $content = $this->showTpltag($content);
        $content = $this->foreachCommand($content);
        $content = $this->forCommand($content);
        $content = $this->setCommand($content);
        $content = $this->ifCommand($content);
        $content = $this->source($content);

        $this->putContent($content, $cache);

    }

    /**
     * 转换
     * @param string $content
     * @param string $cache
     * @return string
     */
    public function show($content = '', $cache = '')
    {

        if (empty($content)) {
            $content = file_get_contents($this->tpl);
        }

        // 只检查第一层的
        if (strpos($content, '@include ') !== false) {
            $content = $this->includeCommand($content);
        }

        if ($this->isParse()) {

            $this->runShow($content, $cache);
            if ($this->isstatic) {
                $data = $this->put($cache ? $cache : $this->cache_tpl);
                fclose($this->tmpfile);
                return $data;
            }
        }

        return $this->cache_tpl;
    }

    /**
     * include tag
     * @param string $content
     * @return null|string|string[]
     */
    public function includeCommand($content = '')
    {
        return preg_replace_callback('/@include\s+([\w\W]*?)(?:[\s]*);/i', function ($mathc) {
            // 此处不做结尾逗号的清理
            if (isset($this->com[md5($mathc[0])])) {
                return $this->com[md5($mathc[0])];
            }
            $file = $mathc[1];
            $contents = '';
            if (strpos($file, ',')) {
                $contents .= '<?php' . PHP_EOL;
                $file = explode(',', $file);
                foreach ($file as $f) {
                    $contents .= ' include \'' . $this->convertFile($f) . "'; \n";
                }
                $contents .= '?\>';
                // $this->com[md5($mathc[0])] = $contents;
                return $contents;
            } else {
                $contents = '<?php include \'' . $this->convertFile($file) . "'; ?>\n";
                return $contents;
            }
        }, $content);
    }

    /**
     * include的内容检查
     * @param $file
     * @return string
     */
    private function convertFile($file)
    {
        if (is_array($file)) {
            $file = current($file);
        }
        $file = str_replace(PHP_EOL, '', $file);
        $f = trim($file);
        $tpl = dirname(dirname($this->tpl)) . '/' . $f . '.html';

        $cache = dirname($this->cache_tpl) . '/' . Loadder::crypt($tpl, Loadder::HAVAL) . '.php';

        $cache_time = filemtime($cache);
        if (PHP_OS == 'Linux') {
            $tpl_time = filectime($tpl);
        } else {
            $tpl_time = filemtime($tpl);
        }

        if (!file_exists($tpl)) {
            throw new \RuntimeException($tpl . ' Not Found');
        }

        if (!file_exists($cache) || $tpl_time > $cache_time) {
            $this->runShow(file_get_contents($tpl), $cache);
        }
        return $cache;
    }

    public function bestatic()
    {
        $this->isstatic = true;
        return $this;
    }

    /**
     * 判断是否需要更新
     * @return bool
     */
    private function isParse()
    {
        if (file_exists($this->cache_tpl)) {
            $cache_time = filemtime($this->cache_tpl);
        }

        if (PHP_OS == 'Linux') {
            $tpl_time = filectime($this->tpl);
        } else {
            $tpl_time = filemtime($this->tpl);
        }

        if (!file_exists($this->cache_tpl) || $cache_time < $tpl_time || $this->isMust) {
            return true;
        }
        return false;
    }

    /**
     * 输出模板内容
     * @param string $content 转换过的内容
     * @param string $cache 输出的缓存文件，空就使用默认
     */
    private function putContent($content = '', $cache = '')
    {
        if (!$this->isstatic) {
            if ($cache == '') {
                $cache = $this->cache_tpl;
            }
            if (!is_dir(dirname($cache))) {
                @mkdir(dirname($cache), 0777, true);
                file_put_contents(dirname($cache) . '/index.html', '');
            }
            file_put_contents($cache, $content);
        }
    }

    public function put($path = '')
    {
        ob_start();
        extract($this->assign, EXTR_SKIP);
        include $path;
        return ob_get_clean();
    }

    private function showVar($content = '')
    {
        $tag = Container::get('config')->get('tpl.parse_func');
        $tag = explode('|', $tag);
        return preg_replace_callback('/\{\{(.*?)\}\}/i', function ($m) use ($tag) {
            if (isset($this->com[hash('sha256', $m[0])])) {
                return $this->com[hash('sha256', $m[0])];
            }
            $s = true;
            $match = trim($m[1]);
            if (strpos($match, '!') === 0) {
                $s = false;
                $match = trim($match, '!');
            }
            $replace = $this->parseVar($match);
            if ($s) {
                $data = '<?php echo ' . $tag[array_rand($tag)] . '(' . $replace . '); ?>';
            } else {
                $data = '<?php echo ' . $replace . '; ?>';
            }
            $this->com[hash('sha256', $m[0])] = $data;
            return $data;
        }, $content);
    }


    private function showFuc($content = '')
    {

        return preg_replace_callback('/\{\[(.*?)\]\}/i', function ($m) {
            if (isset($this->com[hash('sha256', $m[0])])) {
                return $this->com[hash('sha256', $m[0])];
            }
            $match = trim($m[1]);
            $replace = $this->parseFunction($match);
            $data = '<?php ' . $replace . '; ?>';
            $this->com[hash('sha256', $m[0])] = $data;
            return $data;
        }, $content);
    }


    private function showTpltag($content = '')
    {
        return preg_replace_callback('/\{@(.*?)\}/i', function ($m) {
            if (isset($this->com[hash('sha256', $m[0])])) {
                return $this->com[hash('sha256', $m[0])];
            }
            $match = trim($m[1]);
            $data = '<?php echo $tplconfig["' . $match . '"]; ?>';
            $this->com[hash('sha256', $m[0])] = $data;
            return $data;
        }, $content);
    }


}
